package stack.easy;

import jdk.nashorn.internal.runtime.regexp.joni.Regex;

import java.util.*;
import java.util.regex.Pattern;

/**
 * 1. 问题描述
 *      你现在是一场采特殊赛制棒球比赛的记录员。这场比赛由若干回合组成，过去几回合的得分可能会影响以后几回合的得分。
 *      比赛开始时，记录是空白的。你会得到一个记录操作的字符串列表 ops，其中 ops[i] 是你需要记录的第 i 项操作，ops 遵循下述规则：
 *      整数 x - 表示本回合新获得分数 x
 *      "+" - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。
 *      "D" - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。
 *      "C" - 表示前一次得分无效，将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
 *      请你返回记录中所有得分的总和。
 *
 * 2. 算法分析
 *
 *
 * 3. 代码实现
 */
@SuppressWarnings("all")
public class 棒球比赛 {
    public static void main(String[] args) {

    }

    /**
     * 下面的三个方法使用相同的代码不同的栈的结构
     * 在leetcode上提交之后的效率都很低，可能问题出现在代码上，执行效率低的原因是什么呢?
     */

    /**
     * Stack<Integer> stack = new Stack<>();
     * @param ops
     * @return
     */
    public static int calPoints1(String[] ops) {
        // 定义判断数字的正则表达式
        Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
        Stack<Integer> stack = new Stack<>();
        int ans = 0;
        for (String op : ops) {
            // 如果当前为数字
            if (pattern.matcher(op).matches()) {
                stack.add(Integer.parseInt(op));
            }
            else if ("+".equals(op)) {
                int x = stack.pop();
                int y = stack.pop();
                int sum = x + y;
                stack.add(y);
                stack.add(x);
                stack.add(sum);
            }
            else if ("D".equals(op)) {
                // 前一次的分数翻倍
                int x = stack.pop();
                int temp = 2 * x;
                stack.add(x);
                stack.add(temp);
            }
            else if ("C".equals(op)) {
                // 前一次的分数无效
                stack.pop();
            }
        }
        for(int num : stack) {
            ans += num;
        }
        return ans;
    }

    /**
     *  // 定义栈
     *  Deque<Integer> stack = new LinkedList<>();
     * @param ops
     * @return
     */
    public static int calPoints2(String[] ops) {
        // 定义判断数字的正则表达式
        Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
        // 定义栈
        Deque<Integer> stack = new LinkedList<>();
        // 定义结果变量
        int ans = 0;
        // 扫描ops数组
        for(String op : ops) {
            // 当前op为数字
            if(pattern.matcher(op).matches()) {
                stack.push(Integer.parseInt(op));
            }
            // 当前op为D 前一次分数加倍
            else if("D".equals(op)) {
                int lastScore = stack.peek(); // 查看上一次分数
                stack.push(lastScore * 2);
            }
            // 当前op为加号 获取前两次的分数之和
            else if("+".equals(op)) {
                int lastScore = stack.pop();
                int SecondScore = stack.peek();
                int sum = lastScore + SecondScore;
                stack.push(lastScore);
                stack.push(sum);
            }
            // 当前op为C  将上一次得分取消
            else if("C".equals(op)) {
                stack.pop();
            }
        }
        for(int score : stack) {
            ans += score;
        }
        return ans;
    }

    /**
     * // 定义栈
     * Deque<Integer> stack = new ArrayDeque<Integer>();
     * @param ops
     * @return
     */
    public int calPoints3(String[] ops) {
        // 定义判断数字的正则表达式
        Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
        // 定义栈
        Deque<Integer> stack = new ArrayDeque<Integer>();
        // 定义结果变量
        int ans = 0;
        // 扫描ops数组
        for(String op : ops) {
            // 当前op为数字
            if(pattern.matcher(op).matches()) {
                stack.push(Integer.parseInt(op));
            }
            // 当前op为D 前一次分数加倍
            else if("D".equals(op)) {
                int lastScore = stack.peek(); // 查看上一次分数
                stack.push(lastScore * 2);
            }
            // 当前op为加号 获取前两次的分数之和
            else if("+".equals(op)) {
                int lastScore = stack.pop();
                int SecondScore = stack.peek();
                int sum = lastScore + SecondScore;
                stack.push(lastScore);
                stack.push(sum);
            }
            // 当前op为C  将上一次得分取消
            else if("C".equals(op)) {
                stack.pop();
            }
        }
        for(int score : stack) {
            ans += score;
        }
        return ans;
    }

    /**
     * 对上述的优化，将结果的计算放置到for中，省略的最后一个for循环
     * @param ops
     * @return
     */
    public static int calPoints4(String[] ops) {
        // 定义判断数字的正则表达式
        Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
        // 定义栈
        Deque<Integer> stack = new LinkedList<>();
        // 定义结果变量
        int ans = 0;
        // 扫描ops数组
        for(String op : ops) {
            // 当前为数字
            if(pattern.matcher(op).matches()) {
                int temp = Integer.parseInt(op);
                ans += temp;
                stack.push(temp);
            }
            // 当前为D，上一次分数加倍
            else if("D".equals(op)) {
                int lastscore = stack.peek();
                ans += (2 * lastscore);
                stack.push(2 * lastscore);
            }
            // 前两次的分数之和
            else if("+".equals(op)) {
                int lastone = stack.pop();
                int lastsecond = stack.peek();
                int sum = lastone + lastsecond;
                ans += sum;
                stack.push(lastone);
                stack.push(sum);
            } else {
                int lastone = stack.pop();
                ans -= lastone;
            }
        }
        return ans;
    }

    /**
     * 对上述的进一步优化：此时省略了正则表达式，将数字的判断方式到最后的else中
     * 此时我们就可以省略对正则表达式的，这个代码的执行效率要比较高，也就是说之前代码
     * 效率低的原因很可能出现在正则的比较上面
     * @param ops
     * @return
     */
    public int calPoints5(String[] ops) {
        // 定义栈
        Deque<Integer> stack = new LinkedList<>();
        // 定义结果变量
        int ans = 0;
        // 扫描ops数组
        for(String op : ops) {
            if("D".equals(op)) {
                int lastone = stack.peek();
                stack.push(2*lastone);
                ans += (2*lastone);
            } else if("+".equals(op)) {
                int lastone = stack.pop(); int lastsecond = stack.peek();
                int sum = lastone + lastsecond;
                stack.push(lastone); stack.push(sum);
                ans += sum;
            } else if("C".equals(op)) {
                int lastone = stack.pop();
                ans -= lastone;
            } else {
                stack.push(Integer.parseInt(op));
                ans += Integer.parseInt(op);
            }
        }
        return ans;
    }
}
